package main

import (
	"fmt"
	"math"
	"reflect"
	"runtime"
)

/*
func eval(x, y int, op string) int {
	ret := 0
	switch op {
	case "+":
		ret = x + y;
	case "-":
		ret = x -y
	case "*":
		ret = x * y
	case "/":
		ret = x / y
	default:
		panic("error op: "+  op)
	}
	return ret
}*/

func sum(numbs ...int) int {
	s := 0
	for i := range numbs{
		s += numbs[i]
	}
	return s
}

func apply(op func(int, int)int, a, b int) int {
	p := reflect.ValueOf(op).Pointer()
	opName := runtime.FuncForPC(p).Name()
	fmt.Printf("Calling function %s with args " + "(%d, %d) = ", opName, a, b)
	return op(a, b)
}

func eval(x, y int, op string) (int, error) {
	switch op {
	case "+":
		return x + y, nil;
	case "-":
		return  x - y, nil
	case "*":
		return x * y, nil
	case "/":
		if y == 0 {
			return 0, fmt.Errorf("dived value can't equa 0")
		}
		return x / y, nil
	default:
		return 0, fmt.Errorf("error op: " + op)
	}
}

func pow(a, b int) int {
	return int (math.Pow(float64(a), float64(b)))
}

func main() {
	if result, err := eval(3, 0, "/"); err != nil {
		fmt.Println(err)
	} else {
		fmt.Println(result)
	}

	fmt.Println(apply(pow, 3, 4))

	fmt.Println(apply(
		func(a, b int) int {
			return int(math.Pow(float64(a), float64(b)))
		}, 12, 5))

	fmt.Println(apply(
		func(a, b int) int {
			return b - a
		}, 12, 5))

	fmt.Println(sum(3,5,7,9,11,13,15,17))
	fmt.Println(eval(3, 4, "+"))
	fmt.Println(eval(3, 4, "-"))
	fmt.Println(eval(3, 4, "*"))
	fmt.Println(eval(3, 4, "/"))
}
